# -*- coding:utf-8 -*-
from bluepy import btle
from bluepy.btle import Scanner, DefaultDelegate
import prettytable as pt
import ty_cmd_timeout
import time
import eventlet
import threading
import signal

class ScanDelegate(DefaultDelegate):
    def __init__(self):
        DefaultDelegate.__init__(self)

    def handleDiscovery(self, dev, isNewDev, isNewData):
        if isNewDev:
            print "Discovered device", dev.addr
        elif isNewData:
            print "Received new data from", dev.addr
class Ble:
    def __init__(self, addr, addrType):
        self.addr = addr
        self.addrType = addrType

    def set_timeout(num):
        def wrap(func):
            def handle(signum, frame):  # 收到信号 SIGALRM 后的回调函数，第一个参数是信号的数字，第二个参数是the interrupted stack frame.
                raise RuntimeError

            def to_do(*args, **kwargs):
                try:
                    signal.signal(signal.SIGALRM, handle)  # 设置信号和回调函数
                    signal.alarm(num)  # 设置 num 秒的闹钟
                    print 'start alarm signal.'
                    r = func(*args, **kwargs)
                    print 'close alarm signal.'
                    signal.alarm(0)  # 关闭闹钟
                    return r
                except RuntimeError as e:
                    print 'timeout'

            return to_do

        return wrap

    @set_timeout(30)
    def getInfo(self):
        # if properties=='READ', readType and readMsg
        info = {} # {service1:{chara1:[handle, properties, readType, readMsg], chara2}}
        try:
            d = btle.Peripheral(self.addr, self.addrType)
            for ser in d.getServices():
                dict1 = {}
                # 获取不到设备信息，卡在这里了，尝试使用超时时间来跳过
                for chara in ser.getCharacteristics():
                    #time.sleep(5)
                    list1 = []
                    list1.append(str(chara.getHandle()))
                    list1.append(chara.propertiesToString())
                    if (chara.supportsRead()):
                        list1.append(type(chara.read()))
                        list1.append(chara.read())
                    dict1[str(chara)] = list1
                info[str(ser)] = dict1
        except:
            pass
        d.disconnect()
        return info

if __name__ == '__main__':
    scanner = Scanner().withDelegate(ScanDelegate())
    devices = scanner.scan()
    tb = pt.PrettyTable()
    timeout = 5
    t_beginning = time.time()
    tb.field_names = ["MAC", "MAC类型", "信号强度", "Flags", "厂商", "服务(UUID)", "属性", "handle", "ch_type", "detail"]
    for dev in devices:

        print '**************************************************************************'
        print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)
        print dev.getScanData()
        for (adtype, desc, value) in dev.getScanData():
            print "  %s = %s" % (desc, value)
            if desc == 'Manufacturer':
                manufac = value[0:8]
        services = ''
        try:
            eventlet.monkey_patch()
            with eventlet.Timeout(30, True):
                info = Ble(dev.addr, dev.addrType).getInfo()

                for k, v in info.items():
                    if v:
                        for ch, detail in v.items():

                            tb.add_row([dev.addr, dev.addrType, dev.rssi, dev.getScanData()[0][2], manufac, k.split('<')[1].split('>')[0], ch.split('<')[1].split('>')[0], detail[0], detail[1], detail])

        except RuntimeError:
            pass
        except UnboundLocalError:
            pass
        continue
    print tb
